﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using Kawanon.Localization;
using Microsoft.Win32;
using QTPlugin;

namespace Kawanon.QtHoney
{
	public class PluginStringProvider : LocalizedStringProvider
	{
		[ResourceKey("Plugin_Resource")]
		private enum Resources
		{
			Description,
		}

		public override string Author { get { return string.Empty; } }

		public override string Description
		{
			get
			{
				return StringResource.Localize(Resources.Description);
			}
		}

		public override string Name { get { return string.Empty; } }

		public override void SetKey(int iKey)
		{
		}
	}

	[ResourceKey("Misc_Resource")]
	public enum MiscResources
	{
		MyCollectionEditor_DefaultTitle,
		MyCollectionEditor_ValueFormat,
		ChooseFromArrayForm_Text,
		Nothing,
		SuggestionFormat,
		MouseDirectionSymbol,
		RegisterToSystemMenu,
		ConfirmDeleteAllSettings,
		TrailsAlreadyExists,
		ConfirmRevert,
		ExportSettingsTitle,
		ExportSettingsFilter,
		NotSupportedPluginInCallPlugin,
	}

	[ResourceKey("Caption_Resource")]
	public enum Caption
	{
		Error = 0,
		Confirm,
	}

	public class ScrollEffect
	{
		private Timer m_effectTimer;
		private Control m_control;

		public int Frame { get; set; }
		public int Interval { get; set; }
		public bool Visible
		{
			get
			{
				return m_control.Visible;
			}
			set
			{
				SetVisible(value);
			}
		}

		public ScrollEffect(Control control)
		{
			m_control = control;

			Frame = 5;
			Interval = 10;
		}

		public void SetVisible(bool show)
		{
			Size sz = m_control.Size;

			if (m_effectTimer != null)
			{
				m_effectTimer.Stop();
				sz = (Size)m_effectTimer.Tag;
			}

			if (show)
			{
				// これから表示する
				m_control.Height = 0;
			}
			m_control.Visible = true;

			Timer timer = new Timer();
			m_effectTimer = timer;
			int count = Frame;
			int n = 0;

			timer.Tag = sz;
			timer.Interval = Interval;
			timer.Tick += Utility.ToEventHandler(delegate()
			{
				m_control.Height += (sz.Height / count) * (show ? 1 : -1);

				if (++n == count)
				{
					timer.Stop();
					m_control.Visible = show;
					m_control.Height = sz.Height;
				}
			});
			timer.Start();
		}
	}

	public class AlreadyAttachedException : ApplicationException
	{
	}

	public class MyCollectionEditor : CollectionEditor
	{
		private string m_text = StringResource.Localize(MiscResources.MyCollectionEditor_DefaultTitle);

		public MyCollectionEditor(Type t)
			: base(t)
		{
		}

		public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
		{
			try
			{
				string label = (string)Reflection.GetProperty(provider, "PropertyLabel");
				if (label != null)
				{
					m_text = String.Format("{0}", label);
				}
			}
			catch (MissingMethodException ex)
			{
				Utility.ForException(ex);
			}

			return base.EditValue(context, provider, value);
		}

		protected override CollectionEditor.CollectionForm CreateCollectionForm()
		{
			CollectionEditor.CollectionForm form = base.CreateCollectionForm();
			form.Text = m_text;
			return form;
		}
	}

	public class MyCollectionConverter : CollectionConverter
	{
		public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
		{
			if (destinationType == null)
			{
				throw new ArgumentNullException("destinationType");
			}

			if (destinationType == typeof(string))
			{
				if (value is System.Collections.ICollection)
				{
					System.Collections.ICollection c = (System.Collections.ICollection)value;
					//List<string> list = new List<string>();
					//foreach (object o in c)
					//{
					//    list.Add(o.ToString());
					//}
					//return String.Join(", ", list.ToArray());

					return String.Format(
						StringResource.Localize(MiscResources.MyCollectionEditor_ValueFormat),
						c.Count);
				}
			}

			return base.ConvertTo(context, culture, value, destinationType);
		}
	}

	public static class Localizer
	{
		// プラグインの言語ファイルから読み込む？
		// [MainPlugin]
		// Hoge=ほげ
		// ...
		//private static Dictionary<Type, Dictionary<string, string>> s_types = null;

		public static void Replace(Control obj)	// or ListViewItem
		{
			string s = obj.Text;
			//...
			obj.Text = s;
		}

		public static string GetTextByName(string name)	// $(name)
		{
			return null;
		}
	}

	public class PathExpander
	{
		private static Regex s_regCurrentFolder = new Regex("%c%", RegexOptions.Compiled | RegexOptions.IgnoreCase);
		private static Regex s_regFolders = new Regex("%d%", RegexOptions.Compiled | RegexOptions.IgnoreCase);
		private static Regex s_regSelectionOrCurrentFolder = new Regex("%cd%", RegexOptions.Compiled | RegexOptions.IgnoreCase);
		private static Regex s_regFiles = new Regex("%f%", RegexOptions.Compiled | RegexOptions.IgnoreCase);
		private static Regex s_regSelection = new Regex("%s%", RegexOptions.Compiled | RegexOptions.IgnoreCase);

		private string m_currentFolder;
		private string m_selectionOrCurrentFolder;
		private string m_strFiles = String.Empty, m_strFolders = String.Empty, m_strSelection = String.Empty;

		public PathExpander(Address currentFolder, Address[] selection)
		{
			m_currentFolder = Utility.Quote(Utility.AddressToPath(currentFolder));
			m_currentFolder = m_currentFolder != null ? m_currentFolder : String.Empty;

			GenerateStrings(selection);

			m_selectionOrCurrentFolder = (m_strFolders != String.Empty) ? m_strFolders : m_currentFolder;
		}

		private string Concat(string[] paths)
		{
			return String.Join(" ", Array.ConvertAll(paths, path => Utility.Quote(path)));
		}

		private void GenerateStrings(Address[] addrs)
		{
			if (addrs == null)
			{
				return;
			}

			string[] paths = Array.ConvertAll<Address, string>(addrs, Utility.AddressToPath);

			paths = Array.FindAll(paths, path => !String.IsNullOrEmpty(path));
			// 仮想フォルダも含める
			string[] folders = Array.FindAll(paths, path => !File.Exists(path));
			string[] files = Array.FindAll(paths, path => Array.IndexOf(folders, path) == -1);

			m_strSelection = Concat(paths);
			m_strFiles = Concat(files);
			m_strFolders = Concat(folders);
		}

		public string Replace(string str)
		{
			if (str == null)
			{
				return null;
			}
			str = s_regSelection.Replace(str, m_strSelection);
			str = s_regFiles.Replace(str, m_strFiles);
			str = s_regFolders.Replace(str, m_strFolders);
			str = s_regCurrentFolder.Replace(str, m_currentFolder);
			str = s_regSelectionOrCurrentFolder.Replace(str, m_selectionOrCurrentFolder);
			return str;
		}
	}

	public class GroupMenuFactory	// GroupEditor でも使う？ (Server == null でメニューを無効にして)
	{
		public IPluginServer Server { get; set; }
		public bool Expandable { get; set; }
		//public ImageList ImageList { get; set; }

		private ToolStripMenuItem CreateGroupItem(string name, string[] paths)
		{
			ToolStripMenuItem group = new ToolStripMenuItem(name);
			if (paths.Length > 0)
			{
				group.Image = Utility.GetIconBitmap(paths[0], false);
			}

			EventHandler handler = new EventHandler(delegate(object sender, EventArgs e)
			{
				if (Server != null)
				{
					Server.OpenGroup(new string[] { name });
				}
				//group.HideDropDown();	// これは効果が無い？
				group.DropDown = null;
				group.Owner.Hide();
			});

			if (Expandable)
			{
				//group.DoubleClickEnabled = true;
				//group.DoubleClick += handler;
				group.Click += handler;

				foreach (string path in paths)
				{
					ToolStripMenuItem child = new ToolStripMenuItem(
						Utility.IsSpecialFolder(path) ? Utility.GetDisplayName(path) : path);
					//BUG: ImageIndex を指定しても描画されない
					child.Image = Utility.GetIconBitmap(path, false);
					Address addr = new Address(path);	// path を使うと最後の要素になってしまう
					child.Click += new EventHandler(delegate(object sender, EventArgs e)
					{
						if (Server != null)
						{
							Server.CreateTab(addr, -1, false, true);
						}
					});
					group.DropDownItems.Add(child);
				}
			}
			else
			{
				group.Click += handler;
			}
			return group;
		}

		public ToolStripItem[] CreateItems()
		{
			List<ToolStripItem> items = new List<ToolStripItem>();
			RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Quizo\QTTabBar\Groups", false);
			foreach (string name in key.GetValueNames())
			{
				string val = key.GetValue(name) as string;
				if (val == null)
				{
					continue;
				}
				if (val == String.Empty)
				{
					items.Add(new ToolStripSeparator());
					continue;
				}

				string[] paths = val.Split(';');
				ToolStripMenuItem group = CreateGroupItem(name, paths);
				items.Add(group);
			}
			key.Close();
			return items.ToArray();
		}
	}

	public static class Plugins
	{
		// サーバはウィンドウごとに異なる
		//public static IPluginServer Server { get; set; }
		public static List<IPluginClient> Instances { get; private set; }

		static Plugins()
		{
			Instances = new List<IPluginClient>();
		}

		private static Assembly m_serverAssembly;

		public static Assembly ServerAssembly
		{
			get
			{
				if (m_serverAssembly != null)
				{
					return m_serverAssembly;
				}

				Assembly[] asms = AppDomain.CurrentDomain.GetAssemblies();
				m_serverAssembly = Array.Find(asms, asm => asm.FullName.StartsWith("QTTabBar,"));
				return m_serverAssembly;
			}
		}

		public static string GetResourcePath(string name)
		{
			return String.Format("{0}.res.{1}", typeof(Utility).Namespace, name);
		}

		public static string GetLanguageResourcePath(string lang)
		{
			string name = StringResource.ToInternalPath(
				GetResourcePath(String.Format("lang.{0}.xml", lang)));
			// リソースが存在するかチェックする
			if (StringResource.Exists(name))
			{
				return name;
			}
			else
			{
				return null;
			}
		}

		public static string GetLanguageResourcePath()
		{
			string path;
			RegistryKey reg = Plugins.OpenRegistryKey(false);
			if (reg != null)
			{
				path = reg.GetValue("Language") as string;
				reg.Close();
				if (path != null && StringResource.Exists(path))
				{
					return path;
				}
			}
			path = GetLanguageResourcePath(CultureInfo.CurrentUICulture.ThreeLetterISOLanguageName);
			if (path != null)
			{
				return path;
			}
			path = GetLanguageResourcePath(CultureInfo.CurrentCulture.ThreeLetterISOLanguageName);
			if (path != null)
			{
				return path;
			}
			path = GetLanguageResourcePath("eng");
			if (path == null)
			{
				throw new Exception("Default language resource not found");
			}
			return path;
		}

		private static FieldInfo GetNowDebuggingField()
		{
			Type ty = Utility.GetExternalType("QTTabBarLib.QTUtility");
			return ty.GetField("NowDebugging", BindingFlags.NonPublic | BindingFlags.Static);
		}

		public static bool DebugMode
		{
			get
			{
				FieldInfo field = GetNowDebuggingField();
				if (field == null)
				{
					return false;
				}
				return (bool)field.GetValue(null);
			}
			set
			{
				FieldInfo field = GetNowDebuggingField();
				if (field == null)
				{
					return;
				}
				field.SetValue(null, value);
			}
		}

		public static ToolStripRenderer GetMenuRenderer()
		{
			Type t = Utility.GetExternalType("QTTabBarLib.DropDownMenuBase");
			if (t == null)
			{
				return null;
			}
			PropertyInfo prop = t.GetProperty("CurrentRenderer", BindingFlags.Public | BindingFlags.Static);
			return (ToolStripRenderer)prop.GetValue(null, null);
		}

		public static RegistryKey OpenRegistryKey(bool writable)
		{
			return OpenRegistryKey(typeof(Plugins), writable);
		}

		private static RegistryKey OpenRegistryKey(Type t, bool writable)
		{
			string ns = t.Namespace.Replace('.', '\\');
			string key = String.Format(@"Software\Quizo\QTTabBar\Plugins\Settings\{0}", ns);
			if (writable)
			{
				return Registry.CurrentUser.CreateSubKey(key);
			}
			else
			{
				return Registry.CurrentUser.OpenSubKey(key);
			}
		}

		public static RegistryKey OpenClassRegistryKey(Type t, bool writable)
		{
			RegistryKey parent = OpenRegistryKey(writable);
			if (writable)
			{
				return parent.CreateSubKey(t.Name);
			}
			else
			{
				if (parent == null)
				{
					return null;
				}
				return parent.OpenSubKey(t.Name);
			}
		}

		public static event EventHandler SettingsChanged;

		public static void NotifySettingsChanged()
		{
			Utility.Raise(SettingsChanged);
		}
	}

	//public class BarCustomItem : BarButton, IBarCustomItem
	//{
	//    public ToolStripItem CreateItem(bool fLarge, QTPlugin.DisplayStyle displayStyle)
	//    {
	//        return null;
	//    }
	//}


}
